

package	org.jdamico.socks.server.impl;



import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.ServerSocket;
import java.net.Socket;

import org.jdamico.socks.server.commons.Configs;
import org.jdamico.socks.server.commons.DebugLog;
import org.jdamico.socks.server.commons.Utils;



public class ProxyServerInitiator	implements	Runnable
{
	
	protected	Object	m_lock;
	
	protected	Thread			m_TheThread		= null;
	protected	ServerSocket	mProxyServerSocket	= null;
	protected	int				m_nPort			= 0;
	
	public	int		getPort()		{	return	m_nPort;		}

	public	ProxyServerInitiator(int listenPort) {
		m_lock = this;	
		m_nPort			= listenPort;
		DebugLog.getInstance().println( "SOCKS Server Created." );
	}
	
	public	void setLock( Object lock ) {
		this.m_lock = lock;
	}

	public	void start() {
		m_TheThread = new Thread( this );
		m_TheThread.start();
		DebugLog.getInstance().println( "SOCKS Server Started." );
	}

	public	void	stop()	{
		DebugLog.getInstance().println( "SOCKS Server Stopped." );
		m_TheThread.interrupt();
	}
	
	public	void	run(){
		listen();
		
	}

	public	void close() {
		
		if( mProxyServerSocket != null )	{
			try	{
				mProxyServerSocket.close();
			}
			catch( IOException e )	{
			}
		}
		mProxyServerSocket = null;
		DebugLog.getInstance().println( "SOCKS Server Closed." );
	}
	
	public	boolean	isActive()	{
		return	(mProxyServerSocket != null);	
	}
	
	
	private	void prepare()	throws java.net.BindException, IOException {
		synchronized( m_lock )
		{
			mProxyServerSocket = new ServerSocket( m_nPort );
			//mProxyServerSocket.setSoTimeout( Constants.LISTEN_TIMEOUT );
	
			if( m_nPort == 0 )	{
				m_nPort = mProxyServerSocket.getLocalPort();
			}
			DebugLog.getInstance().println( "SOCKS Server Listen at Port : " + m_nPort );
		}
	}
	
	protected	void listen() {
	
		try
		{
			prepare();
			startListen();
		}
		catch( java.net.BindException e )	{
			DebugLog.getInstance().error( "The Port "+m_nPort+" is in use !" );
			DebugLog.getInstance().error( e );
		}
		catch( IOException e )	{
			DebugLog.getInstance().error( "IO Error Binding at port : "+m_nPort );
		}catch( Exception e )	{
			DebugLog.getInstance().error( "IO Error Binding at port : "+m_nPort );
		}finally {
			close();
		}
		
	}

	private void startListen() {
		while( isActive() )	{
			waitToAcceptClientConnection();
			Thread.yield();
		}
	}
	
	public	void waitToAcceptClientConnection()	{
		synchronized( m_lock )
		{
			if( mProxyServerSocket == null )	return;
	
			try
			{
				Socket clientSocket = mProxyServerSocket.accept();
				clientSocket.setSoTimeout( Configs.DEFAULT_SERVER_TIMEOUT );
				clientSocket.setTcpNoDelay(true);
				clientSocket.setReuseAddress(true);
				DebugLog.getInstance().println( "Connection from : " + Utils.getSocketInfo( clientSocket ) );
				ProxyHandler proxy = new ProxyHandler(clientSocket );
				proxy.start();
			}
			catch( InterruptedIOException e )		{
				DebugLog.getInstance().error( e );
			}
			catch( Exception e )	{
				DebugLog.getInstance().error( e );
			}
		}	// synchronized
	}
}

